package net.sf.rose.business.bean.action;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.rose.jdbc.DBUtils;
import net.sf.rose.jdbc.DataParser;
import net.sf.rose.jdbc.GenericDAO;
import net.sf.rose.jdbc.PageBean;
import net.sf.rose.jdbc.QueryMapSQL;
import net.sf.rose.jdbc.bean.FieldBean;
import net.sf.rose.jdbc.service.Service;

import org.apache.commons.lang.StringUtils;
import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.Default;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Root;

/**
 * 数据库查询执行单元
 * @author fengjian
 * @since 2014-3-27
 */
@Default
@Root(name = "actionSearch")
public class ActionUnitSearchBean extends Action {

	/** SQL语句 */
	@Element
	private String sql = null;

	/** 是否缓存 */
	@Attribute(required = false)
	private boolean cache = false;

	/** 数据库查询返回结果名称 */
	@ElementList(required = false)
	private List<String> cacheNameList = null;

	/** 参数列表 */
	@ElementList(required = false)
	private List<ParamemterBean> paramenters = new ArrayList<ParamemterBean>();

	public List<String> getCacheNameList() {
		return cacheNameList;
	}

	public void setCacheNameList(List<String> cacheNameList) {
		this.cacheNameList = cacheNameList;
	}

	public boolean isCache() {
		return cache;
	}

	public void setCache(boolean cache) {
		this.cache = cache;
	}

	public String getSql() {
		return sql;
	}

	public void setSql(String sql) {
		this.sql = sql;
	}

	public List<ParamemterBean> getParamenters() {
		return paramenters;
	}

	public void setParamenters(List<ParamemterBean> paramenters) {
		this.paramenters = paramenters;
	}

	/**
	 * 执行自定义操作
	 * @param request 	- Http请求
	 * @param response  - Http返回
	 * @param service 	- 数据库连接服务类 
	 * @param map 		- 前台传过来的数据
	 * @param data		- 上下文返回的数据
	 */
	public void execute(HttpServletRequest request, HttpServletResponse response, 
			Service service, Map<String, Object> map, Map<String, Object> data) {
		// 如果有缓存，则从缓存中取值
		if (this.isCache() && this.cacheNameList != null) {
			for(String key : this.cacheNameList){
				Object obj = DBUtils.getCache(key);
				if (obj != null) {
					data.put(key, obj);
					return;
				}
			}
		}
		this.search(request, response, service, map, data);
	}

	/**
	 * 执行自定义操作
	 * @param request 	- Http请求
	 * @param response  - Http返回
	 * @param service 	- 数据库连接服务类 
	 * @param map 		- 前台传过来的数据
	 * @param data		- 上下文返回的数据
	 */
	protected void search(HttpServletRequest request, HttpServletResponse response, 
			Service service, Map<String, Object> map, Map<String, Object> data) {
		// 拼接数据库查询SQL语句和参数列表
		String key = null;
		Object val = null;
		String sql = null;
		String this_sql = this.sql;
		this.cacheNameList = new ArrayList<String>();
		Map<String, Object> params = new HashMap<String, Object>();
		if (this.getParamenters() != null) {
			Map<String, FieldBean> fields = null;
			DataParser paser = new DataParser();
			for (ParamemterBean bean : this.getParamenters()) {
				sql = null;
				key = bean.getFieldName();
				val = getValue(key, map, data);
				// 如果参数的值没有取到，就使用默认值
				if (val == null) {
					val = bean.getDefaultValue();
				}
				String[] arr = StringUtils.split(key, '.');
				if (fields == null) {
					fields = DBUtils.getFields(arr[0]);
				}
				FieldBean field = fields.get(arr[1]);
				// 如果从此表字段集中取不到数据，而且前台数据的表名前缀和现用的表字段集不一样
				if (field == null && !fields.get(0).getTable().equals(arr[0])) {
					// 重新根据表名称取表字段属性集
					fields = DBUtils.getFields(arr[0]);
					field = fields.get(arr[1]);
				}
				// 如果参数的值取到了
				if (val != null) {
					sql = bean.getReplaceName();
					// 如果是字符串类型
					if (field.isStringType()) {
						// 使用模糊查询
						val = sql.indexOf(" like ") != -1 ? "%" + val + '%' : val;
					}
					// 如果是数字类型
					else if (field.isNumberType()) {
						val = paser.parse(field.getJavaType(), val, null);
					}
					params.put(bean.getFieldName(), val);
				}
				// 如果参数值没有取到
				else {
					// 如果是日期类型
					if (field.isDateType()) {
						// 尝试取开始日期
						String key_fr = key + "_from";
						Object frVal = data.get(key_fr);
						if (frVal != null) {
							frVal = paser.parse(field.getJavaType(), frVal, null);
						}
						// 尝试取结束日期
						String key_to = key + "_to";
						Object to_Val = data.get(key_to);
						if (to_Val != null) {
							to_Val = paser.parse(field.getJavaType(), to_Val, null);
						}
						StringBuffer sb = new StringBuffer();
						// 拼接日期比较查询SQL语句
						if (frVal != null || to_Val != null) {
							sb.append(" AND (");
							if (frVal != null) {
								sb.append(bean.getSearchName()).append(">=#").append(bean.getFieldName()).append("# ");
								params.put(bean.getFieldName(), frVal);
								if (to_Val != null) {
									sb.append(" AND ").append(bean.getSearchName()).append("<=#").append(bean.getFieldName()).append("# ");
									params.put(bean.getFieldName(), frVal);
								}
							} else {
								if (to_Val != null) {
									sb.append(" AND ").append(bean.getSearchName()).append("<=#").append(bean.getFieldName()).append("# ");
									params.put(bean.getFieldName(), frVal);
								}
							}
							sb.append(')');
							sql = sb.toString();
						}
					}
					// 如果是强制
					if (sql == null && bean.isForce()) {
						sql = " AND " + bean.getSearchName() + "=null ";
					}
				}
				sql = sql == null ? "" : sql;
				key = "{" + bean.getSearchName() + '}';
				this_sql = StringUtils.replace(this_sql, key, sql);
			}
		}
		// 执行数据库查询操作
		val = null;
		GenericDAO dao = new GenericDAO(service);
		QueryMapSQL query = new QueryMapSQL(service);
		String[] sqls = StringUtils.split(this_sql, ';');
		for (String str : sqls) {
			int index = str.indexOf('=');
			key = str.substring(0, index).trim();
			sql = str.substring(index + 1, str.length()).trim();
			query.createListSql(sql, params);
			// 取得指定查询结果的数据类型
			index = key.lastIndexOf('_');
			String beanName = key.substring(0, index).trim();
			String type = key.substring(index + 1, key.length()).trim();
			// 如果指定查询结果的数据类型是单个数据类
			if (type.equals(DBUtils.TYPE_LOAD)) {
				val = dao.load(query);
			}
			// 指定查询结果的数据类型是Map，则根据主键将List转换成Map类
			else if (type.equals(DBUtils.TYPE_MAP)) {
				index = beanName.indexOf('_');
				String mapKey = beanName.substring(index + 1, beanName.length()).trim();
				beanName = beanName.substring(0, index).trim();
				List<?> list = dao.list(query);
				Map<Object, Object> m = new java.util.HashMap<Object, Object>();
				for (Object o : list) {
					Map<?, ?> d = (Map<?, ?>) o;
					m.put(d.get(mapKey), d);
				}
				val = m;
			}
			// 指定查询结果的数据类型是List
			else if (type.equals(DBUtils.TYPE_LIST)) {
				val = dao.list(query);
			}
			// 指定查询结果的数据类型是分页List
			else if (type.equals(DBUtils.TYPE_PAGE)) {
				PageBean page = new PageBean();
				Object o = map.get(PageBean.PAGING_CURRENT_PAGE);
				page.setCurrentPage((o != null) ? Integer.parseInt(o.toString()) : 0);
				o = map.get(PageBean.PAGING_PAGE_SIZE);
				page.setpageSize((o != null) ? Integer.parseInt(o.toString()) : 0);
				query.setPage(page);
				dao.list(query);
				val = page;
			}
			// 如果使用缓存，则加入缓存中。
			if (this.isCache()) {
				DBUtils.putCache(beanName, val);
				this.cacheNameList.add(beanName);
			}
			data.put(beanName, val);
		}
	}

	/**
	 * 从前台传来的数据集或上下文中取得键所对应的值
	 * @param key       - 键值
	 * @param map     - 前台传过来的数据
	 * @param data     - 上下文数据
	 * @return Object  - 查询结果数据类
	 */
	@SuppressWarnings("unchecked")
	public Object getValue(String key, Map<String, Object> map, Map<String, Object> data) {
		Object val = map.get(key);
		if (val != null) {
			return val;
		} 
		// 如果根据键名没取到值
		else {
			// 如果键是表名加字段名
			if (key.indexOf('.') != -1) {
				String[] arr = StringUtils.split(key, '.');
				val = map.get(arr[1]);
				// 如果根据字段名取到值
				if (val != null) {
					return val;
				} 
				// 如果还是没有,则放弃从前台传入的数据中取值;改从上下文数据结构中取值
				else {
					// 根据键名取值
					val = data.get(key);
					if (val != null) {
						return val;
					} 
					// 如果根据键名没取到值
					else {
						// 根据字段名取值
						Object obj = data.get(arr[0]);
						if (obj != null && obj instanceof Map) {
							data = (Map<String, Object>) obj;
							val = data.get(arr[1]);
						}
					}
				}
			}
		}
		return val;
	}
}
